﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace MLopez.BizVal.CW.Base
{
    /// <summary>
    /// Esta clase encapsula una Jerarquía Lingüística de varios niveles    
    /// </summary>
    public class Jerarquia:IEnumerable<ConjuntoEtiquetas>
    {   
        Dictionary<int, ConjuntoEtiquetas> jerarquia;
                
        string name = string.Empty;

        /// <summary>
        /// Nombre de la jerarquía
        /// </summary>
        public string Nombre
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Número de niveles de la jerarquía
        /// </summary>
        public int Niveles
        {
            get
            {
                return jerarquia.Count;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nivel"></param>
        /// <returns></returns>
        public ConjuntoEtiquetas this[int nivel]
        {
            get
            {
                if (jerarquia.ContainsKey(nivel))
                    return jerarquia[nivel];
                else
                    throw new CWException(CWExceptionType.IndexOutOfRange);
            }
        }

        public TriEtiqueta this[int nivel, int indice]
        {
            get
            {
                if (jerarquia.ContainsKey(nivel))                    
                    return jerarquia[nivel][indice];
                else
                    throw new CWException(CWExceptionType.IndexOutOfRange);
            }
        }

        /// <summary>
        /// Crea una nueva jerarquía vacía
        /// </summary>
        public Jerarquia()
        {
            jerarquia = new Dictionary<int, ConjuntoEtiquetas>();
        }
        
        /// <summary>
        /// Crea una nueva jerarquía con el número de niveles indicado
        /// El nivel más bajo tendrá la granularidad indicada en el segundo parámetro
        /// La granularidad g(n+1) del nivel T+1 vendrá dada por la siguiente expresión
        /// g(n+1) = 2*g(n) - 1
        /// </summary>
        /// <param name="niveles">Número de niveles de la jerarquía</param>
        /// <param name="granularidadMinima">Granularidad del nivel inferior</param>
        public Jerarquia(int niveles, int granularidadMinima)
        {
            int granularidad = 0;
            int cont = 0;            
            granularidad = granularidadMinima;
            jerarquia = new Dictionary<int, ConjuntoEtiquetas>();

            for (cont = 0; cont < niveles; cont++)
            {
                AddNivel(granularidad);                
                granularidad = (2 * granularidad) - 1;
            }
        }

        public Jerarquia(int niveles, int granularidadMinima, string nombre):this(niveles,granularidadMinima)
        {
            this.Nombre = nombre;
        }

        /// <summary>
        /// Añade un nivel a la jerarquía con la granularidad indicada.   
        /// Si el nivel ya existe, no se realizará acción alguna.
        /// </summary>
        /// <param name="granularidad">Granularidad del nivel a introducir</param>
        public ConjuntoEtiquetas AddNivel(int granularidad)
        {
            if (!jerarquia.ContainsKey(granularidad))
            {
                ConjuntoEtiquetas nivel = new ConjuntoEtiquetas(granularidad);
                jerarquia.Add(granularidad, nivel);
                return nivel;
            }
            else
                return null;
        }

        public bool ContieneNivel(int nivel)
        {
            return jerarquia.ContainsKey(nivel);
        }
        

        ///// <summary>
        ///// Función de transformación de información dentro de la jerarquía
        ///// Transforma una 2-tupla representando información en un nivel
        ///// a una 2-tupla equivalente en el nivel indicado como nivel destino
        ///// </summary>
        ///// <param name="tuplaOrigen">2-tupla representando la información a transformar</param>
        ///// <param name="nivelDestino">Nivel de la jerarquía en el que queremos obtener la 2-tupla equivalente</param>
        ///// <returns>2-tupla que representa la información en el nivel destino</returns>
        ///// <exception cref="CWException">
        ///// Si el nivel de origen de la 2-tupla o el nivel de destino no existen en la jerarquía
        ///// </exception>
        //public DosTupla TF(DosTupla tuplaOrigen, int nivelDestino)
        //{
        //    DosTupla retorno;            
        //    int nivelOrigen = tuplaOrigen.Nivel;
        //    if ((jerarquia.ContainsKey(nivelOrigen)) && (jerarquia.ContainsKey(nivelDestino)))
        //    {
        //        ConjuntoEtiquetas conjuntoOrigen = jerarquia[nivelOrigen];
        //        ConjuntoEtiquetas conjuntoDestino = jerarquia[nivelDestino];
        //        decimal dividendo = conjuntoOrigen.DeltaInversa(tuplaOrigen) * (nivelDestino - 1);
        //        decimal valor = dividendo / (nivelOrigen - 1);
        //        retorno = conjuntoDestino.Delta(valor);
        //    }
        //    else
        //        throw new CWException(CWExceptionType.HierarchyLevelMissed);
        //    return retorno;           
        //}



        public IEnumerator<ConjuntoEtiquetas> GetEnumerator()
        {
            return jerarquia.Values.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return jerarquia.Values.GetEnumerator();
        }
    }
}
